/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.meanzoft.m3d.model.m3dmodel;

import java.util.LinkedList;
import static org.lwjgl.opengl.GL11.*;
import org.lwjgl.util.vector.Vector2f;
import org.lwjgl.util.vector.Vector3f;
import org.meanzoft.m3d.model.mdx.GeoSet;
import org.meanzoft.m3d.model.mdx.MDXHeader;
import org.meanzoft.m3d.resource.ResourceManager;
import org.meanzoft.m3d.scene.Renderable;
import org.meanzoft.m3d.scene.SceneNode;

/**
 *
 * @author Meanz
 */
public class Model extends SceneNode implements Renderable {

    private ModelData modelData;
    private LinkedList<Mesh> meshes;
    public MDXHeader header;
    private int listId = -1;
    private String name;
    public LinkedList<GeoSet> geos = new LinkedList<GeoSet>();

    public Model() {
        this("default");
    }

    public Model(String name) {
        this.name = name;
        modelData = new ModelData();
        meshes = new LinkedList<Mesh>();
    }

    public void addMesh(Mesh mesh) {
        meshes.add(mesh);
    }

    /**
     * Info
     */
    /**
     * Functions
     */
    public void compile() {
        if (true) {
            compileGeo();
            return;
        }
        listId = glGenLists(1);


        for (int i = 0; i < meshes.size(); i++) {
            Mesh mesh = meshes.get(i);
            glNewList(listId + i, GL_COMPILE);
            {
                glBegin(GL_POLYGON);
                {
                    /**
                     * Ignore edges and vertices
                     * Will figure out what to do with them later
                     */
                    if (mesh.getFaces().size() > 0) {
                        for (Face face : mesh.getFaces()) {

                            /**
                             * Assign normal
                             */
                            if (face.getNormalPoint1() != -1) {
                                glNormal3v(modelData.getNormals().get(face.getNormalPoint1()).to3fVector());
                            }
                            /**
                             * Assign texture coordinate
                             */
                            if (face.getTexPoint1() != -1) {
                                glTexCoord2v(modelData.getTextureCoordinates().get(face.getTexPoint1()));
                            }
                            /**
                             * Assign vertex coordinate
                             */
                            glVertex3v(modelData.getVertices().get(face.getFacePoint1()).to3fVector());

                            /**
                             * Assign normal
                             */
                            if (face.getNormalPoint2() != -1) {
                                glNormal3v(modelData.getNormals().get(face.getNormalPoint2()).to3fVector());
                            }
                            /**
                             * Assign texture coordinate
                             */
                            if (face.getTexPoint2() != -1) {
                                glTexCoord2v(modelData.getTextureCoordinates().get(face.getTexPoint2()));
                            }
                            /**
                             * Assign vertex coordinate
                             */
                            glVertex3v(modelData.getVertices().get(face.getFacePoint2()).to3fVector());

                            /**
                             * Assign normal
                             */
                            if (face.getNormalPoint3() != -1) {
                                glNormal3v(modelData.getNormals().get(face.getNormalPoint3()).to3fVector());
                            }
                            /**
                             * Assign texture coordinate
                             */
                            if (face.getTexPoint3() != -1) {
                                glTexCoord2v(modelData.getTextureCoordinates().get(face.getTexPoint3()));
                            }
                            /**
                             * Assign vertex coordinate
                             */
                            glVertex3v(modelData.getVertices().get(face.getFacePoint3()).to3fVector());
                        }
                    }

                }
                glEnd();
            }
            glEndList();
        }
    }

    public void compileGeo() {
        listId = glGenLists(geos.size());
        int off = 0;
        for (GeoSet geo : geos) {
            glNewList(listId + off, GL_COMPILE);
            {
                glBegin(GL_TRIANGLES);
                {
                    for (int i = 0; i < geo.faceList.size(); i++) {
                        glNormal3v(geo.normalList.get((int) geo.faceList.get(i).x));
                        glTexCoord2v(geo.texCoords.get((int) geo.faceList.get(i).x));
                        glVertex3v(geo.vertexList.get((int) geo.faceList.get(i).x));
                        
                        glNormal3v(geo.normalList.get((int) geo.faceList.get(i).y));
                        glTexCoord2v(geo.texCoords.get((int) geo.faceList.get(i).y));
                        glVertex3v(geo.vertexList.get((int) geo.faceList.get(i).y));
                        
                        glNormal3v(geo.normalList.get((int) geo.faceList.get(i).z));
                        glTexCoord2v(geo.texCoords.get((int) geo.faceList.get(i).z));
                        glVertex3v(geo.vertexList.get((int) geo.faceList.get(i).z));
                    }
                }
                glEnd();
            }
            glEndList();
            off++;
        }
    }

    public void update() {
    }

    public void render() {
        glPushMatrix();
        {
            ResourceManager.getManager().getTexture("sado").bind();
            glScalef(0.01f, 0.01f, 0.01f);
            glRotatef(-90f, 1f, 0f, 0f);
            for (int i = 0; i < geos.size(); i++) {
                glCallList(listId + i);
            }
        }
        glPopMatrix();
        ResourceManager.getManager().getTexture("_surf").bind();
        if (true) {
            return;
        }
        glPushMatrix();
        {
            ResourceManager.getManager().getTexture("sado").bind();
            glScalef(0.01f, 0.01f, 0.01f);
            glRotatef(-90f, 1f, 0f, 0f);
            for (int i = 0; i < meshes.size(); i++) {
                glCallList(listId + i);
            }
        }
        glPopMatrix();
        ResourceManager.getManager().getTexture("_surf").bind();
    }

    /**
     * Ref
     */
    public void glNormal3v(Vector3f normal) {
        glNormal3f(normal.x, normal.y, normal.z);
    }

    public void glVertex3v(Vector3f vector) {
        glVertex3f(vector.x, vector.y, vector.z);
    }

    public void glTexCoord2v(Vector2f texCoord) {
        glTexCoord2f(texCoord.x, texCoord.y);
    }

    /**
     * Getters and Setters
     */
    public int getListId() {
        return listId;
    }

    public void setListId(int listId) {
        this.listId = listId;
    }

    public LinkedList<Mesh> getMeshes() {
        return meshes;
    }

    public void setMeshes(LinkedList<Mesh> meshes) {
        this.meshes = meshes;
    }

    public ModelData getModelData() {
        return modelData;
    }

    public void setModelData(ModelData modelData) {
        this.modelData = modelData;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
